import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;

import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;


public class Gen3  extends ImageStack{
	//static String slash="/";//mac
		//windows
		static String slash ="\\";
	static final int INITIAL_SIZE = 100;
	String path, basename, basetime, endtime,xOverlap, yOverlap,basetype;
	int nSlices, mode,dur;
	String[] names;
	public static File folder;
	public int xStart, yStart, xEnd, yEnd, xWidth, yHeight,zDepth, fuseMode;
	public ArrayList<String> channelList;
	public Gen3(int squareSize, String xO, String yO, int width, int height, int z, ArrayList<String> cL, File path, String etime) {
		//super(width, height);
		folder = path;
		xWidth = width;
		yHeight =height;
		xStart = 0;
		yStart = 0;
		xEnd = squareSize;
		yEnd = squareSize;
		zDepth =z;
		nSlices =z;
		mode = 1;
		fuseMode =1;
		xOverlap = xO;
		yOverlap =yO;
		endtime =etime;
		dur = Integer.parseInt(endtime)+1;
		channelList= cL;		
		this.path = path.getName();
		names = new String[INITIAL_SIZE];
	}
	//Constructor for pos
	public Gen3(int xS, int xE, int yS, int yE,String btype, String xO, String yO, int width, int height, int z, ArrayList<String> cL, File path, String etime) {
		
		//super(width, height);
		folder = path;
		xWidth = width;
		yHeight =height;
		xStart = xS;
		yStart = yS;
		xEnd = xE;
		yEnd = yE;
		zDepth =z;
		nSlices =z;
		mode = 2;
		fuseMode = 1;
		xOverlap = xO;
		yOverlap =yO;
		endtime =etime;
		dur = Integer.parseInt(endtime)+1;
		channelList= cL;		
		this.path = path.getName();
		names = new String[INITIAL_SIZE];
		basetype =btype;
	}
	
	/** Returns the pixel array for the specified slice, were 1<=n<=nslices. */
	public Object getPixels(int n) {
		//System.gc();
		ImageProcessor ip = getProcessor(n);
		if (ip!=null)
			return ip.getPixels();
		else
			return null;
	}		
	public ImageProcessor getProcessor(int n) {
		int zSlicer = ((n-1)%(channelList.size()*zDepth))/channelList.size();
		int chSlicer = ((n-1)%(channelList.size()*zDepth))%channelList.size();
		int tSlicer = (n-1)/(channelList.size()*zDepth);
	 	String pathOpened="";	
		ImagePlus toAdd;		
		ImageProcessor toAddProcessor, ip;					
		float[] ipPixels, grabber;
		int xPixOverlap= xWidth*Integer.parseInt(xOverlap)/100;
		int yPixOverlap= yHeight*Integer.parseInt(yOverlap)/100;
		ipPixels= new float[((xWidth*(yEnd-yStart+1))-(yPixOverlap*(yEnd-yStart)))*((yHeight*(xEnd-xStart+1))-(xPixOverlap*(xEnd-xStart)))];
		IJ.log(""+((xWidth*(yEnd-yStart+1))-(yPixOverlap*(yEnd-yStart)))*((yHeight*(xEnd-xStart+1))-(xPixOverlap*(xEnd-xStart))));
		if(mode==1){//Grids
			int numPixLine= xWidth*(xEnd-xStart+1)-xPixOverlap*(xEnd-xStart); 
			int numPixRow= yHeight*numPixLine;	
			int temp = yStart;
			yStart = xStart;
			xStart = yStart;
			temp = xEnd;
			xEnd = yEnd;
			yEnd =temp;
			for(int xPos=xStart; xPos<=xEnd;xPos++){
				for(int yPos = yStart; yPos<=yEnd;yPos++){
					pathOpened = folder.getAbsolutePath()+slash+"Grid_"+String.format("%01d",yPos)+"_"+String.format("%01d",xPos)+slash+"img_"+String.format("%09d",tSlicer)+"_"+channelList.get(chSlicer)+"_"+String.format("%03d",zSlicer)+".tif";							
					File tempFile = new File(pathOpened);
					if( tempFile.exists()){ 
						toAdd = IJ.openImage(pathOpened);
						toAdd=IJ.openImage(pathOpened);
						toAddProcessor = toAdd.getProcessor().toFloat(0, null);
						toAddProcessor.flipHorizontal();
						grabber = (float[])toAddProcessor.getPixels();
						
						for(int y=0; y<yHeight; y++){
							for (int x=0; x<xWidth; x++){
								ipPixels[(x+((yPos-yStart)*(xWidth-xPixOverlap))+ //line
									y*numPixLine+ //lines
									((xPos-xStart)*(numPixRow-(yPixOverlap*numPixLine))))] //col
									= fuse(ipPixels[(x+((yPos-yStart)*(xWidth-xPixOverlap))+ //line
									y*numPixLine+ //lines
									((xPos-xStart)*(numPixRow-(yPixOverlap*numPixLine))))],grabber[y*xWidth+x]);
							}
						}
					}else{
						IJ.log("Missing File:"+pathOpened);
						grabber = new float[xWidth*yHeight];
						Arrays.fill(grabber,(float) 0);
						for(int y=0; y<yHeight; y++){
							for (int x=0; x<xWidth; x++){
								ipPixels[(x+((yPos-yStart)*(xWidth-xPixOverlap))+ //line
									y*numPixLine+ //lines
									((xPos-xStart)*(numPixRow-(yPixOverlap*numPixLine))))] //col
									= fuse(ipPixels[(x+((yPos-yStart)*(xWidth-xPixOverlap))+ //line
									y*numPixLine+ //lines
									((xPos-xStart)*(numPixRow-(yPixOverlap*numPixLine))))],grabber[y*xWidth+x]);
							}
						}
					}
						
				}
			}ip = new FloatProcessor((xWidth*(xEnd-xStart+1))-(xPixOverlap*(xEnd-xStart)),(yHeight*(yEnd-yStart+1))-(yPixOverlap*(yEnd-yStart)));		
			ip.setPixels(ipPixels);
			return ip;
		}else{//Positions
			int numPixLine= xWidth*(xEnd-xStart+1)-xPixOverlap*(xEnd-xStart); 
			int numPixRow= yHeight*numPixLine;	
			for(int xPos=yStart; xPos<=yEnd;xPos++){
				for(int yPos = xStart; yPos<=xEnd;yPos++){
					pathOpened = folder.getAbsolutePath()+slash+basetype+"_"+String.format("%03d",xPos)+"_"+String.format("%03d",yPos)+slash+"img_"+String.format("%09d",tSlicer)+"_"+channelList.get(chSlicer)+"_"+String.format("%03d",zSlicer)+".tif";							
					File tempFile = new File(pathOpened);
					if( tempFile.exists()){ 	
						toAdd = IJ.openImage(pathOpened);
						toAddProcessor = toAdd.getProcessor().toFloat(0, null);
						grabber = (float[])toAddProcessor.getPixels();
						for(int y=0; y<yHeight; y++){
							for (int x=0; x<xWidth; x++){
								ipPixels[(x+((yPos-xStart)*(xWidth-xPixOverlap))+ //line
									y*numPixLine+ //lines
									((xPos-yStart)*(numPixRow-(yPixOverlap*numPixLine))))] //col
									= fuse(ipPixels[(x+((yPos-xStart)*(xWidth-xPixOverlap))+ //line
									y*numPixLine+ //lines
									((xPos-yStart)*(numPixRow-(yPixOverlap*numPixLine))))],grabber[y*xWidth+x]);
								
							}
						}	
					}else{
						IJ.log("Missing File:"+pathOpened);
						grabber = new float[xWidth*yHeight];
						Arrays.fill(grabber,(float) 0);
						for(int y=0; y<yHeight; y++){
							for (int x=0; x<xWidth; x++){
								ipPixels[(x+((xPos-xStart)*(xWidth-xPixOverlap))+ //line
									y*numPixLine+ //lines
									((xPos-xStart)*(numPixRow-(yPixOverlap*numPixLine))))] //col
									= fuse(ipPixels[(x+((yPos-yStart)*(xWidth-xPixOverlap))+ //line
									y*numPixLine+ //lines
									((xPos-xStart)*(numPixRow-(yPixOverlap*numPixLine))))],grabber[y*xWidth+x]);
							}
						}
					}
				}
			}
			ip = new FloatProcessor((xWidth*(xEnd-xStart+1))-(xPixOverlap*(xEnd-xStart)),(yHeight*(yEnd-yStart+1))-(yPixOverlap*(yEnd-yStart)));			
			ip.setPixels(ipPixels);
			return ip;
		}
	}
		
		public float fuse(float val1, float val2){
	 		float fused=val2;
	 		switch(fuseMode){
	 			case 0://add
	 				fused = (float)(val1+val2);
	 				break;	
	 			case 1: 	//max	
	 				if (val1>val2){
	 					fused = val1;	
	 				}
					break;
				case 2://NEEDTOFIX!!!!!!!!!! HOW?
					if(val1!=0){
						fused = (float)((val1+val2)/2);
					}
					break;
	 		}	
	 		return fused;
	 	}
		 /** Returns the number of slices in this stack. */
		public int getSize() {
			return nSlices*channelList.size()*dur;
		}
		
		/** Returns the file name of the Nth image. */
		public String getSliceLabel(int n) {
			 return "";
		}
		
		/** Returns null. */
		public Object[] getImageArray() {
			return null;
		}

	   /** Does nothing. */
		public void setSliceLabel(String label, int n) {
		}

		/** Always return true. */
		public boolean isVirtual() {
			return true;
		}

	   /** Does nothing. */
		public void trim() {
		}
		public int getWidth(){
			return xWidth;	
		}
		public int getHeight(){
			return yHeight;
		}
		public int getNFrames(){
			return dur;
		}

		public ImageStack getImageStack(){
			return this;
		}
		public void setPixels(Object pixels, int n) {
		}
}